/**
 * 安全工具类
 * Security Utilities
 */

const crypto = require('crypto');
const bcrypt = require('bcryptjs');
const validator = require('validator');
const xss = require('xss');
const securityConfig = require('../config/security');
const logger = require('./logger');

class SecurityUtils {
  /**
   * 生成安全的随机字符串
   */
  static generateSecureToken(length = 32) {
    return crypto.randomBytes(length).toString('hex');
  }

  /**
   * 生成CSRF token
   */
  static generateCSRFToken() {
    return crypto.randomBytes(32).toString('hex');
  }

  /**
   * 验证CSRF token
   */
  static validateCSRFToken(token, sessionToken) {
    if (!token || !sessionToken) {
      return false;
    }
    return crypto.timingSafeEqual(
      Buffer.from(token, 'hex'),
      Buffer.from(sessionToken, 'hex')
    );
  }

  /**
   * 哈希密码
   */
  static async hashPassword(password) {
    const saltRounds = 12;
    return await bcrypt.hash(password, saltRounds);
  }

  /**
   * 验证密码
   */
  static async verifyPassword(password, hashedPassword) {
    return await bcrypt.compare(password, hashedPassword);
  }

  /**
   * 验证密码强度
   */
  static validatePasswordStrength(password) {
    const config = securityConfig.validation.password;
    const errors = [];

    if (password.length < config.minLength) {
      errors.push(`密码至少需要${config.minLength}个字符`);
    }

    if (password.length > config.maxLength) {
      errors.push(`密码不能超过${config.maxLength}个字符`);
    }

    if (config.requireUppercase && !/[A-Z]/.test(password)) {
      errors.push('密码必须包含大写字母');
    }

    if (config.requireLowercase && !/[a-z]/.test(password)) {
      errors.push('密码必须包含小写字母');
    }

    if (config.requireNumbers && !/\d/.test(password)) {
      errors.push('密码必须包含数字');
    }

    if (config.requireSpecialChars && !/[!@#$%^&*(),.?":{}|<>]/.test(password)) {
      errors.push('密码必须包含特殊字符');
    }

    return {
      isValid: errors.length === 0,
      errors
    };
  }

  /**
   * 清理XSS
   */
  static sanitizeInput(input, options = {}) {
    if (typeof input !== 'string') {
      return input;
    }

    const xssOptions = {
      whiteList: options.allowedTags || securityConfig.xss.allowedTags,
      stripIgnoreTag: true,
      stripIgnoreTagBody: ['script', 'style', 'iframe', 'object', 'embed']
    };

    return xss(input, xssOptions);
  }

  /**
   * 递归清理对象中的XSS
   */
  static sanitizeObject(obj, options = {}) {
    if (typeof obj === 'string') {
      return this.sanitizeInput(obj, options);
    }

    if (Array.isArray(obj)) {
      return obj.map(item => this.sanitizeObject(item, options));
    }

    if (obj && typeof obj === 'object') {
      const sanitized = {};
      for (const key in obj) {
        if (obj.hasOwnProperty(key)) {
          sanitized[key] = this.sanitizeObject(obj[key], options);
        }
      }
      return sanitized;
    }

    return obj;
  }

  /**
   * 检测SQL注入
   */
  static detectSQLInjection(input) {
    if (typeof input !== 'string') {
      return false;
    }

    const patterns = securityConfig.sqlInjection.suspiciousPatterns;
    return patterns.some(pattern => pattern.test(input));
  }

  /**
   * 验证邮箱
   */
  static validateEmail(email) {
    const config = securityConfig.validation.email;
    
    if (!email || typeof email !== 'string') {
      return { isValid: false, error: '邮箱不能为空' };
    }

    if (email.length > config.maxLength) {
      return { isValid: false, error: `邮箱长度不能超过${config.maxLength}个字符` };
    }

    if (!config.pattern.test(email)) {
      return { isValid: false, error: '邮箱格式不正确' };
    }

    if (!validator.isEmail(email)) {
      return { isValid: false, error: '邮箱格式不正确' };
    }

    return { isValid: true };
  }

  /**
   * 验证用户名
   */
  static validateNickname(nickname) {
    const config = securityConfig.validation.nickname;
    
    if (!nickname || typeof nickname !== 'string') {
      return { isValid: false, error: '用户名不能为空' };
    }

    if (nickname.length < config.minLength || nickname.length > config.maxLength) {
      return { 
        isValid: false, 
        error: `用户名长度必须在${config.minLength}-${config.maxLength}个字符之间` 
      };
    }

    if (!config.pattern.test(nickname)) {
      return { 
        isValid: false, 
        error: '用户名只能包含字母、数字、中文、下划线和连字符' 
      };
    }

    return { isValid: true };
  }

  /**
   * 验证文件名
   */
  static validateFilename(filename) {
    const config = securityConfig.validation.filename;
    
    if (!filename || typeof filename !== 'string') {
      return { isValid: false, error: '文件名不能为空' };
    }

    if (filename.length > config.maxLength) {
      return { isValid: false, error: `文件名长度不能超过${config.maxLength}个字符` };
    }

    if (!config.pattern.test(filename)) {
      return { isValid: false, error: '文件名包含非法字符' };
    }

    // 检查是否为危险文件扩展名
    const ext = filename.toLowerCase().substring(filename.lastIndexOf('.'));
    if (securityConfig.fileUpload.blockedExtensions.includes(ext)) {
      return { isValid: false, error: `不允许的文件类型: ${ext}` };
    }

    return { isValid: true };
  }

  /**
   * 验证文件路径
   */
  static validateFilePath(filePath) {
    if (!filePath || typeof filePath !== 'string') {
      return { isValid: false, error: '文件路径不能为空' };
    }

    // 防止目录遍历攻击
    if (filePath.includes('..') || filePath.includes('~') || filePath.startsWith('/')) {
      return { isValid: false, error: '文件路径不合法' };
    }

    // 检查路径中的每个部分
    const parts = filePath.split('/');
    for (const part of parts) {
      if (part && !securityConfig.validation.filename.pattern.test(part)) {
        return { isValid: false, error: '文件路径包含非法字符' };
      }
    }

    return { isValid: true };
  }

  /**
   * 生成安全的文件名
   */
  static generateSecureFilename(originalName) {
    const ext = originalName.substring(originalName.lastIndexOf('.'));
    const name = originalName.substring(0, originalName.lastIndexOf('.'));
    const timestamp = Date.now();
    const random = crypto.randomBytes(8).toString('hex');
    
    // 清理文件名，只保留安全字符
    const safeName = name.replace(/[^a-zA-Z0-9\u4e00-\u9fa5_-]/g, '_');
    
    return `${safeName}_${timestamp}_${random}${ext}`;
  }

  /**
   * 检查IP是否在白名单中
   */
  static isIPWhitelisted(ip) {
    const config = securityConfig.ipControl;
    
    if (!config.whitelistEnabled) {
      return true;
    }

    return config.whitelist.includes(ip);
  }

  /**
   * 检查IP是否在黑名单中
   */
  static isIPBlacklisted(ip) {
    const config = securityConfig.ipControl;
    
    if (!config.blacklistEnabled) {
      return false;
    }

    return config.blacklist.includes(ip);
  }

  /**
   * 记录安全事件
   */
  static logSecurityEvent(event, details = {}) {
    if (!securityConfig.logging.enabled) {
      return;
    }

    const logData = {
      timestamp: new Date().toISOString(),
      event,
      ...details
    };

    logger.warn('Security Event:', logData);
  }

  /**
   * 生成内容摘要（用于完整性检查）
   */
  static generateContentHash(content) {
    return crypto.createHash('sha256').update(content).digest('hex');
  }

  /**
   * 验证内容摘要
   */
  static verifyContentHash(content, expectedHash) {
    const actualHash = this.generateContentHash(content);
    return crypto.timingSafeEqual(
      Buffer.from(actualHash, 'hex'),
      Buffer.from(expectedHash, 'hex')
    );
  }

  /**
   * 加密敏感数据
   */
  static encryptSensitiveData(data, key) {
    const algorithm = 'aes-256-gcm';
    const iv = crypto.randomBytes(16);
    const cipher = crypto.createCipher(algorithm, key);
    
    let encrypted = cipher.update(data, 'utf8', 'hex');
    encrypted += cipher.final('hex');
    
    const authTag = cipher.getAuthTag();
    
    return {
      encrypted,
      iv: iv.toString('hex'),
      authTag: authTag.toString('hex')
    };
  }

  /**
   * 解密敏感数据
   */
  static decryptSensitiveData(encryptedData, key) {
    const algorithm = 'aes-256-gcm';
    const decipher = crypto.createDecipher(algorithm, key);
    
    decipher.setAuthTag(Buffer.from(encryptedData.authTag, 'hex'));
    
    let decrypted = decipher.update(encryptedData.encrypted, 'hex', 'utf8');
    decrypted += decipher.final('utf8');
    
    return decrypted;
  }

  /**
   * 生成API密钥
   */
  static generateAPIKey() {
    return crypto.randomBytes(32).toString('base64');
  }

  /**
   * 验证API密钥格式
   */
  static validateAPIKey(apiKey) {
    if (!apiKey || typeof apiKey !== 'string') {
      return false;
    }

    // API密钥应该是64个字符的base64字符串
    return /^[A-Za-z0-9+/]{43}=$/.test(apiKey);
  }
}

module.exports = SecurityUtils;